subroutine allocate_snapshot
  use log
  use params_and_constants
  use particles
  implicit  none

  write(logunit,*)'   -allocating snapshot memory'

  if(allocated(Type0)) deallocate(Type0)
  allocate(Type0(0:Header%NumPart_Total(0)-1))
  if(.not.(allocated(Type0))) call abort("Failed to allocate Type0")

  if(allocated(Type1)) deallocate(Type1)
  allocate(Type1(0:Header%NumPart_Total(1)-1))
  if(.not.(allocated(Type1))) call abort("Failed to allocate Type1")

  if(allocated(Type2)) deallocate(Type2)
  allocate(Type2(0:Header%NumPart_Total(2)-1))
  if(.not.(allocated(Type2))) call abort("Failed to allocate Type2")

  if(allocated(Type3)) deallocate(Type3)
  allocate(Type3(0:Header%NumPart_Total(3)-1))
  if(.not.(allocated(Type3))) call abort("Failed to allocate Type3")

  if(allocated(Type4)) deallocate(Type4)
  allocate(Type4(0:Header%NumPart_Total(4)-1))
  if(.not.(allocated(Type4))) call abort("Failed to allocate Type4")

  if(allocated(Type5)) deallocate(Type5)
  allocate(Type5(0:Header%NumPart_Total(5)-1))
  if(.not.(allocated(Type5))) call abort("Failed to allocate Type5")

  write(logunit,*)'    -done'
  call flush(logunit)

end subroutine allocate_snapshot

! --------------------------------

subroutine allocate_tmp_selection
  use log
  use params_and_constants
  use particles
  implicit none

  write(logunit,*)'   -allocating temporary (unsorted) selection memory'

  if(allocated(Type0_tmp)) deallocate(Type0_tmp)
  allocate(Type0_tmp(0:Header%NumPart_Total(0)-1))
  if(.not.(allocated(Type0_tmp))) call abort("Failed to allocate Type0_tmp")

  if(allocated(Type1_tmp)) deallocate(Type1_tmp)
  allocate(Type1_tmp(0:Header%NumPart_Total(1)-1))
  if(.not.(allocated(Type1_tmp))) call abort("Failed to allocate Type1_tmp")

  if(allocated(Type2_tmp)) deallocate(Type2_tmp)
  allocate(Type2_tmp(0:Header%NumPart_Total(2)-1))
  if(.not.(allocated(Type2_tmp))) call abort("Failed to allocate Type2_tmp")

  if(allocated(Type3_tmp)) deallocate(Type3_tmp)
  allocate(Type3_tmp(0:Header%NumPart_Total(3)-1))
  if(.not.(allocated(Type3_tmp))) call abort("Failed to allocate Type3_tmp")

  if(allocated(Type4_tmp)) deallocate(Type4_tmp)
  allocate(Type4_tmp(0:Header%NumPart_Total(4)-1))
  if(.not.(allocated(Type4_tmp))) call abort("Failed to allocate Type4_tmp")

  if(allocated(Type5_tmp)) deallocate(Type5_tmp)
  allocate(Type5_tmp(0:Header%NumPart_Total(5)-1))
  if(.not.(allocated(Type5_tmp))) call abort("Failed to allocate Type5_tmp")

 
end subroutine allocate_tmp_selection

! --------------------------------

subroutine deallocate_tmp_selection
  use log
  use params_and_constants
  use particles
  implicit none

  write(logunit,*)'   -dellocating temporary (unsorted) selection memory'

  if(allocated(Type0_tmp)) deallocate(Type0_tmp)
  if(allocated(Type1_tmp)) deallocate(Type1_tmp)
  if(allocated(Type2_tmp)) deallocate(Type2_tmp)
  if(allocated(Type3_tmp)) deallocate(Type3_tmp)
  if(allocated(Type4_tmp)) deallocate(Type4_tmp)
  if(allocated(Type5_tmp)) deallocate(Type5_tmp)

end subroutine deallocate_tmp_selection

! --------------------------------

subroutine allocate_selection
  use log
  use params_and_constants
  use particles
  implicit none

  write(logunit,*)'   -allocating sorted selection memory'

  if(allocated(Type0_Selection)) deallocate(Type0_Selection)
  allocate(Type0_Selection(0:Header%NumPart_Total(0)-1))
  if(.not.(allocated(Type0_Selection))) call abort("Failed to allocate Type0_Selection")

  if(allocated(Type1_Selection)) deallocate(Type1_Selection)
  allocate(Type1_Selection(0:Header%NumPart_Total(1)-1))
  if(.not.(allocated(Type1_Selection))) call abort("Failed to allocate Type1_Selection")

  if(allocated(Type2_Selection)) deallocate(Type2_Selection)
  allocate(Type2_Selection(0:Header%NumPart_Total(2)-1))
  if(.not.(allocated(Type2_Selection))) call abort("Failed to allocate Type2_Selection")

  if(allocated(Type3_Selection)) deallocate(Type3_Selection)
  allocate(Type3_Selection(0:Header%NumPart_Total(3)-1))
  if(.not.(allocated(Type3_Selection))) call abort("Failed to allocate Type3_Selection")

  if(allocated(Type4_Selection)) deallocate(Type4_Selection)
  allocate(Type4_Selection(0:Header%NumPart_Total(4)-1))
  if(.not.(allocated(Type4_Selection))) call abort("Failed to allocate Type4_Selection")

  if(allocated(Type5_Selection)) deallocate(Type5_Selection)
  allocate(Type5_Selection(0:Header%NumPart_Total(5)-1))
  if(.not.(allocated(Type5_Selection))) call abort("Failed to allocate Type5_Selection")


end subroutine allocate_selection

! --------------------------------

subroutine allocate_traced
  use log
  use params_and_constants
  use particles
  implicit none
  
  integer*4 :: nType0
  integer*4 :: nType1
  integer*4 :: nType2
  integer*4 :: nType3
  integer*4 :: nType4
  integer*4 :: nType5

  write(logunit,*)'    -allocating tracing memory'

  ! Note that we don't need to allocate too much memory here as we know the maximum 
  ! possible number of particles of each type that might appear in each snapshot just 
  ! from particle conservation arguments
  nType0 = NumSelected(0)+NumSelected(4) ! these are conserved collectively
  nType1 = NumSelected(1)                ! these are conserved individually
  nType2 = NumSelected(2)                ! these are conserved individually
  nType3 = NumSelected(3)                ! these are conserved individually
  nType4 = NumSelected(4)                ! final number is maximum possible
  nType5 = NumSelected(5)                ! these are conserved individually

  if(allocated(Type0_Traced_Index)) deallocate(Type0_Traced_Index)
  allocate(Type0_Traced_Index(0:nType0-1))
  if(.not.(allocated(Type0_Traced_Index))) call abort("Failed to allocate Type0_Traced_Index")

  if(allocated(Type1_Traced_Index)) deallocate(Type1_Traced_Index)
  allocate(Type1_Traced_Index(0:nType1-1))
  if(.not.(allocated(Type1_Traced_Index))) call abort("Failed to allocate Type1_Traced_Index")

  if(allocated(Type2_Traced_Index)) deallocate(Type2_Traced_Index)
  allocate(Type2_Traced_Index(0:nType2-1))
  if(.not.(allocated(Type2_Traced_Index))) call abort("Failed to allocate Type2_Traced_Index")

  if(allocated(Type3_Traced_Index)) deallocate(Type3_Traced_Index)
  allocate(Type3_Traced_Index(0:nType3-1))
  if(.not.(allocated(Type3_Traced_Index))) call abort("Failed to allocate Type3_Traced_Index")

  if(allocated(Type4_Traced_Index)) deallocate(Type4_Traced_Index)
  allocate(Type4_Traced_Index(0:nType4-1))
  if(.not.(allocated(Type4_Traced_Index))) call abort("Failed to allocate Type4_Traced_Index")

  if(allocated(Type5_Traced_Index)) deallocate(Type5_Traced_Index)
  allocate(Type5_Traced_Index(0:nType5-1))
  if(.not.(allocated(Type5_Traced_Index))) call abort("Failed to allocate Type5_Traced_Index")

  ! Initialise
  Type0_Traced_Index(:) = -1
  Type1_Traced_Index(:) = -1
  Type2_Traced_Index(:) = -1
  Type3_Traced_Index(:) = -1
  Type4_Traced_Index(:) = -1
  Type5_Traced_Index(:) = -1

end subroutine allocate_traced

! --------------------------------

subroutine allocate_selection_preknown
  use log
  use params_and_constants
  use particles
  implicit none

  write(logunit,*)'   -allocating sorted selection memory'

  if(allocated(Type0_Selection)) deallocate(Type0_Selection)
  allocate(Type0_Selection(0:NumSelected(0)-1))
  if(.not.(allocated(Type0_Selection))) call abort("Failed to allocate Type0_Selection")

  if(allocated(Type1_Selection)) deallocate(Type1_Selection)
  allocate(Type1_Selection(0:NumSelected(1)-1))
  if(.not.(allocated(Type1_Selection))) call abort("Failed to allocate Type1_Selection")

  if(allocated(Type2_Selection)) deallocate(Type2_Selection)
  allocate(Type2_Selection(0:NumSelected(2)-1))
  if(.not.(allocated(Type2_Selection))) call abort("Failed to allocate Type2_Selection")

  if(allocated(Type3_Selection)) deallocate(Type3_Selection)
  allocate(Type3_Selection(0:NumSelected(3)-1))
  if(.not.(allocated(Type3_Selection))) call abort("Failed to allocate Type3_Selection")

  if(allocated(Type4_Selection)) deallocate(Type4_Selection)
  allocate(Type4_Selection(0:NumSelected(4)-1))
  if(.not.(allocated(Type4_Selection))) call abort("Failed to allocate Type4_Selection")

  if(allocated(Type5_Selection)) deallocate(Type5_Selection)
  allocate(Type5_Selection(0:NumSelected(5)-1))
  if(.not.(allocated(Type5_Selection))) call abort("Failed to allocate Type5_Selection")

end subroutine allocate_selection_preknown
